package com.donger.sso.system.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.donger.common.core.utils.BizException;
import com.donger.sso.login.entity.LoginData;
import com.donger.sso.system.dto.UserDTO;
import com.donger.sso.system.entity.SysUser;
import com.donger.sso.system.mapper.SysUserMapper;
import com.donger.sso.utils.AuthUtils;
import io.vavr.control.Try;
import lombok.AllArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.validation.Valid;
import java.util.List;

/**
 * service
 *
 * @author pmc
 */
@Service
@AllArgsConstructor
public class SysUserService extends ServiceImpl<SysUserMapper, SysUser> {

    private final static PasswordEncoder ENCODER = new BCryptPasswordEncoder();


    /**
     * 保存用户信息
     * 保存用户
     *
     * @param user 需要保存的用户
     */
    public void saveUser(@Valid UserDTO user) {
        /**
         * 校验参数是否正确
         * 判断是新增该是修改
         * 新增时 是否有重复数据
         * 返回完成信息
         */

        checkUser(user, false);
        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(user, sysUser);
        this.save(sysUser);
    }


    /**
     * 更新用户信息
     *
     * @param user
     */
    public void updateUser(@Valid UserDTO user) {
        AuthUtils.CACHE_MAP.remove(String.valueOf(user.getId()));
        // 直接对用户新增更新
        checkUser(user, true);
        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(user, sysUser);
        this.updateById(sysUser);
    }


    /**
     * 检查是否有重复数据
     *
     * @param userDTO
     * @return
     */
    private void checkUser(UserDTO userDTO, boolean yourself) {
        List<SysUser> sysUsers = baseMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                .ne(yourself, SysUser::getId, userDTO.getId())
                .and(i -> i.eq(SysUser::getPhone, userDTO.getPhone())
                        .or()
                        .eq(SysUser::getUsername, userDTO.getUsername())
                )
        );
        if (CollUtil.isNotEmpty(sysUsers)) {
            throw new BizException("用户名或手机号重复");

        }
    }

    /**
     * 使用用户名登陆
     *
     * @param name
     * @param pwd
     */
    public LoginData loginByUsername(String name, String pwd) {

        Try<SysUser> sysUsers = Try.of(() -> {
            // 只查询管理员，其他用户不能使用改功能登陆
            return baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                    .eq(SysUser::getUsername, name)
                    .eq(SysUser::getStatus, "Y")
            );
        });
        if (sysUsers.isFailure()) {
            throw new BizException("查询用户失败或用户被锁定");
        }
        SysUser sysUser = sysUsers.get();
        Boolean booleans = checkPassword(sysUser, pwd);
        if (!booleans) {
            throw new BizException("用户名或密码输入错误");
        }
        // 进行登陆
        StpUtil.login(sysUser.getId());

        String tokenValue = StpUtil.getTokenValue();
        return LoginData.builder()
                .phone(sysUser.getPhone())
                .token(tokenValue)
                .userId(sysUser.getId())
                .userName(sysUser.getUsername())
                .truename(sysUser.getTruename())
                .build();
    }

    /**
     * 校验密码是否正确
     *
     * @param user
     * @param password
     * @return
     */
    private Boolean checkPassword(SysUser user, String password) {
        return ENCODER.matches(password, user.getPassword());
    }
}
